package org.dromara.hotel.util;


import java.util.*;

public class RuleEngineUtil {
    // 支持的运算符优先级（值越大优先级越高）
    private static final Map<String, Integer> OPERATOR_PRECEDENCE = createOperatorPrecedence();

    private static Map<String, Integer> createOperatorPrecedence() {
        Map<String, Integer> precedence = new HashMap<>();
        precedence.put("||", 1);
        precedence.put("&&", 2);
        precedence.put("==", 3);
        precedence.put("!=", 3);
        precedence.put(">", 4);
        precedence.put("<", 4);
        precedence.put(">=", 4);
        precedence.put("<=", 4);
        precedence.put("+", 5);
        precedence.put("-", 5);
        precedence.put("*", 6);
        precedence.put("/", 6);
        precedence.put("%", 6);
        return Collections.unmodifiableMap(precedence);
    }

    /**
     * 执行条件判断
     * @param condition 条件字符串，如 "a > 5 && (b < 10 || c == 20)"
     * @param params 参数 Map，如 {a=6, b=8, c=20}
     * @return 判断结果
     */
    public static boolean evaluate(String condition, Map<String, Number> params) {
        List<Token> tokens = tokenize(condition);
        Node ast = buildAST(tokens);
        Object result = evaluateAST(ast, params);
        if (result instanceof Boolean) {
            return (Boolean) result;
        } else {
            throw new IllegalArgumentException("条件表达式的结果应为布尔值");
        }
    }

    /**
     * 执行公式计算
     * @param expression 公式字符串，如 "(price * discount) + quantity"
     * @param params 参数 Map
     * @return 计算结果
     */
    public static double evaluateExpression(String expression, Map<String, Number> params) {
        List<Token> tokens = tokenize(expression);
        Node ast = buildAST(tokens);
        Object result = evaluateAST(ast, params);
        if (result instanceof Number) {
            return ((Number) result).doubleValue();
        } else {
            throw new IllegalArgumentException("公式表达式的结果应为数值");
        }
    }

    // ========================== 词法分析 ==========================
    private enum TokenType { VARIABLE, NUMBER, OPERATOR, PAREN }

    private static class Token {
        final TokenType type;
        final String value;

        Token(TokenType type, String value) {
            this.type = type;
            this.value = value;
        }
    }

    private static List<Token> tokenize(String condition) {
        List<Token> tokens = new ArrayList<>();
        int pos = 0;
        while (pos < condition.length()) {
            char c = condition.charAt(pos);
            if (Character.isWhitespace(c)) {
                pos++;
                continue;
            }

            // 处理数字或负号开头的数字
            int numPos = tryTokenizeNumber(condition, tokens, pos);
            if (numPos != pos) {
                pos = numPos;
                continue;
            }

            // 处理变量
            if (Character.isLetter(c) || c == '_') {
                StringBuilder sb = new StringBuilder();
                while (pos < condition.length() &&
                    (Character.isLetterOrDigit(condition.charAt(pos)) || condition.charAt(pos) == '_')) {
                    sb.append(condition.charAt(pos++));
                }
                tokens.add(new Token(TokenType.VARIABLE, sb.toString()));
                continue;
            }

            // 处理括号
            if (c == '(' || c == ')') {
                tokens.add(new Token(TokenType.PAREN, String.valueOf(c)));
                pos++;
                continue;
            }

            // 处理多字符运算符
            if (pos < condition.length() - 1) {
                String twoCharOp = condition.substring(pos, pos + 2);
                if (OPERATOR_PRECEDENCE.containsKey(twoCharOp)) {
                    tokens.add(new Token(TokenType.OPERATOR, twoCharOp));
                    pos += 2;
                    continue;
                }
            }

            // 处理单字符运算符
            String singleCharOp = String.valueOf(c);
            if (OPERATOR_PRECEDENCE.containsKey(singleCharOp)) {
                tokens.add(new Token(TokenType.OPERATOR, singleCharOp));
                pos++;
                continue;
            }

            throw new IllegalArgumentException("无效字符: " + c);
        }
        return tokens;
    }

    private static int tryTokenizeNumber(String condition, List<Token> tokens, int pos) {
        int originalPos = pos;
        boolean isNegative = false;

        if (pos < condition.length() && condition.charAt(pos) == '-') {
            if (pos == 0 || isPreviousTokenOperatorOrLeftParen(tokens)) {
                isNegative = true;
                pos++;
            } else {
                return originalPos;
            }
        }

        int start = pos;
        boolean hasDecimal = false;
        while (pos < condition.length()) {
            char c = condition.charAt(pos);
            if (Character.isDigit(c)) {
                pos++;
            } else if (c == '.' && !hasDecimal) {
                hasDecimal = true;
                pos++;
            } else {
                break;
            }
        }

        if (pos > start) {
            String number = (isNegative ? "-" : "") + condition.substring(start, pos);
            tokens.add(new Token(TokenType.NUMBER, number));
            return pos;
        } else {
            return originalPos;
        }
    }

    private static boolean isPreviousTokenOperatorOrLeftParen(List<Token> tokens) {
        if (tokens.isEmpty()) return false;
        Token last = tokens.get(tokens.size() - 1);
        return last.type == TokenType.OPERATOR ||
            (last.type == TokenType.PAREN && last.value.equals("("));
    }

    // ========================== 语法分析 ==========================
    private interface Node {
        Object evaluate(Map<String, Number> params);
    }

    private static class ValueNode implements Node {
        private final String value;

        ValueNode(String value) {
            this.value = value;
        }

        @Override
        public Object evaluate(Map<String, Number> params) {
            try {
                return Double.parseDouble(value);
            } catch (NumberFormatException e) {
                return params.getOrDefault(value, 0).doubleValue();
            }
        }
    }

    private static class OperatorNode implements Node {
        private final String operator;
        private final Node left;
        private final Node right;

        OperatorNode(String operator, Node left, Node right) {
            this.operator = operator;
            this.left = left;
            this.right = right;
        }

        @Override
        public Object evaluate(Map<String, Number> params) {
            if (isArithmeticOperator()) {
                double leftVal = getNumber(left.evaluate(params));
                double rightVal = getNumber(right.evaluate(params));
                return evaluateArithmetic(leftVal, rightVal);
            } else if (isComparisonOperator()) {
                double leftVal = getNumber(left.evaluate(params));
                double rightVal = getNumber(right.evaluate(params));
                return evaluateComparison(leftVal, rightVal);
            } else if (isLogicalOperator()) {
                return evaluateLogical(params);
            } else {
                throw new IllegalArgumentException("未知运算符: " + operator);
            }
        }

        private boolean isArithmeticOperator() {
            return "+".equals(operator) || "-".equals(operator) || "*".equals(operator) ||
                "/".equals(operator) || "%".equals(operator);
        }

        private double evaluateArithmetic(double a, double b) {
            switch (operator) {
                case "+": return a + b;
                case "-": return a - b;
                case "*": return a * b;
                case "/": return a / b;
                case "%": return a % b;
                default: throw new IllegalStateException();
            }
        }

        private boolean isComparisonOperator() {
            return ">".equals(operator) || "<".equals(operator) || ">=".equals(operator) ||
                "<=".equals(operator) || "==".equals(operator) || "!=".equals(operator);
        }

        private Boolean evaluateComparison(double a, double b) {
            switch (operator) {
                case ">": return a > b;
                case "<": return a < b;
                case ">=": return a >= b;
                case "<=": return a <= b;
                case "==": return a == b;
                case "!=": return a != b;
                default: throw new IllegalStateException();
            }
        }

        private boolean isLogicalOperator() {
            return "&&".equals(operator) || "||".equals(operator);
        }

        private Boolean evaluateLogical(Map<String, Number> params) {
            boolean a = getBoolean(left.evaluate(params));
            if ("&&".equals(operator) && !a) return false;
            if ("||".equals(operator) && a) return true;
            boolean b = getBoolean(right.evaluate(params));
            return "&&".equals(operator) ? a && b : a || b;
        }

        private double getNumber(Object value) {
            if (value instanceof Number) {
                return ((Number) value).doubleValue();
            }
            throw new IllegalArgumentException("期望数值类型");
        }

        private boolean getBoolean(Object value) {
            if (value instanceof Boolean) {
                return (Boolean) value;
            }
            throw new IllegalArgumentException("期望布尔类型");
        }
    }

    // 使用 Shunting-yard 算法构建 AST
    private static Node buildAST(List<Token> tokens) {
        Stack<Node> output = new Stack<>();
        Stack<String> operators = new Stack<>();

        for (Token token : tokens) {
            switch (token.type) {
                case VARIABLE:
                case NUMBER:
                    output.push(new ValueNode(token.value));
                    break;
                case OPERATOR:
                    while (!operators.isEmpty() && !"(".equals(operators.peek()) &&
                        OPERATOR_PRECEDENCE.get(operators.peek()) >= OPERATOR_PRECEDENCE.get(token.value)) {
                        pushOperatorNode(operators.pop(), output);
                    }
                    operators.push(token.value);
                    break;
                case PAREN:
                    if ("(".equals(token.value)) {
                        operators.push("(");
                    } else {
                        while (!"(".equals(operators.peek())) {
                            pushOperatorNode(operators.pop(), output);
                        }
                        operators.pop(); // 弹出 "("
                    }
                    break;
            }
        }

        while (!operators.isEmpty()) {
            pushOperatorNode(operators.pop(), output);
        }

        return output.pop();
    }

    private static void pushOperatorNode(String operator, Stack<Node> output) {
        Node right = output.pop();
        Node left = output.pop();
        output.push(new OperatorNode(operator, left, right));
    }

    private static Object evaluateAST(Node node, Map<String, Number> params) {
        return node.evaluate(params);
    }

    // ========================== 使用示例 ==========================
    public static void main(String[] args) {
        Map<String, Number> params = Map.of(
            "base", 10000
        );

        // 条件判断示例
//        String condition1 = "price > 100 && quantity <= 10";
//        System.out.println(evaluate(condition1, params)); // true
//
//        String condition2 = "(price * discount) >= 95 || quantity == 5";
//        System.out.println(evaluate(condition2, params)); // true (96 >=95)
//
//        // 公式计算示例
//        String expression1 = "price * discount + quantity";
//        System.out.println(evaluateExpression(expression1, params)); // 120*0.8 +5 = 101.0

        String expression2 = "base*1.2";
        System.out.println(evaluateExpression(expression2, params)); // (8)*(20)/2 = 80.0
    }
}
